package helper

import (
	"cloud-disk/core/define"
	"context"
	"crypto/md5"
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/jordan-wright/email"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	uuid "github.com/satori/go.uuid"
	"math/rand"
	"net/http"
	"net/smtp"
	"os"
	"path"
	"time"
)

func Md5(s string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}

// GenerateToken 生成token
func GenerateToken(id uint64, identity, name string) (string, error) {
	uc := define.UserClaim{
		Id:       id,
		Name:     name,
		Identity: identity,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, uc)
	tokenString, err := token.SignedString([]byte(define.JwtKey))
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

// AnalyzeToken
// Token 解析
func AnalyzeToken(token string) (*define.UserClaim, error) {
	uc := new(define.UserClaim)
	claims, err := jwt.ParseWithClaims(token, uc, func(token *jwt.Token) (interface{}, error) {
		return []byte(define.JwtKey), nil
	})
	if err != nil {
		return nil, err
	}
	if !claims.Valid {
		return uc, errors.New("token is invalid")
	}
	return uc, err
}

// MailSendCode 邮箱验证码发送
func MailSendCode(mail, code string) error {
	e := email.NewEmail()
	// 发送人
	e.From = "Get <ketianlin@126.com>"
	// 接收人
	e.To = []string{mail}
	e.Subject = "验证码发送测试"
	e.HTML = []byte(fmt.Sprintf("你的验证码为：<h1>%s</h1>", code))
	err := e.SendWithTLS("smtp.126.com:465", smtp.PlainAuth("", "ketianlin@126.com", define.MailPassword, "smtp.126.com"),
		&tls.Config{InsecureSkipVerify: true, ServerName: "smtp.126.com"})
	if err != nil {
		return err
	}
	return nil
}

// RandCode 生成随机数
func RandCode() string {
	s := "1234567890"
	code := ""
	// 时间戳的种子
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < define.CodeLength; i++ {
		//code += fmt.Sprintf("%c", s[rand.Intn(len(s))])
		code += string(s[rand.Intn(len(s))])
	}
	return code
}

func UUID() string {
	return uuid.NewV4().String()
}

// GetFileContentType 获取文件类型
func GetFileContentType(output *os.File) (string, error) {
	// 仅嗅探内容类型的第一个
	// 使用了 512 个字节。
	buf := make([]byte, 512)
	_, err := output.Read(buf)
	if err != nil {
		return "", err
	}
	// 真正起作用的函数
	contentType := http.DetectContentType(buf)
	return contentType, nil
}

// MinIOUpload 上传到自建的minio中
func MinIOUpload(r *http.Request) (string, error) {
	minioClient, err := minio.New(define.MinIOEndpoint, &minio.Options{
		Creds: credentials.NewStaticV4(define.MinIOAccessKeyID, define.MinIOAccessSecretKey, ""),
	})
	if err != nil {
		return "", err
	}

	// 获取文件信息
	file, fileHeader, err := r.FormFile("file")
	bucketName := define.MinIOBucket
	objectName := fmt.Sprintf("%s%s", UUID(), path.Ext(fileHeader.Filename))

	_, err = minioClient.PutObject(context.Background(), bucketName, objectName, file, fileHeader.Size, minio.PutObjectOptions{ContentType: "binary/octet-stream"})
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s/%s/%s", define.MinIOBucket, bucketName, objectName), nil
}
